LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
USE ieee.std_logic_unsigned.all;

ENTITY Communication IS
	PORT(
		Clk : IN std_logic;
		Reset : IN std_logic;
		
		GameMode : IN std_logic_vector(1 downto 0);
		-- Key Switch
		LocalP2KeyState : IN std_logic_vector(5 DOWNTO 0);
		P2KeyState : OUT std_logic_vector(5 DOWNTO 0);
		-- COM Ports
		RxD : IN std_logic;
		TxD : OUT std_logic;
		-- SecoRam Switch
		SecoAddr    	: OUT std_logic_vector(9 downto 0);
		SecoReadData 	: IN std_logic_vector(15 DOWNTO 0);
		SecoWriteData   : OUT  std_logic_vector(15 downto 0);
		SecoWriteEnable : OUT std_logic;
		
		DebugSignal : OUT std_logic_vector(2 DOWNTO 0)
	);
END Communication;

ARCHITECTURE rtl OF Communication IS
	
	COMPONENT async_transmitter
		PORT(
			clk : in std_logic;
			TxD_start : in std_logic;
			TxD_data : in std_logic_vector(7 downto 0);
			TxD : out std_logic;
			TxD_busy : out std_logic
			);
	END COMPONENT;
	
	COMPONENT async_receiver
	PORT(
			clk : IN std_logic;
			RxD : IN std_logic;
			RxD_data_ready : OUT std_logic;
			RxD_data : OUT std_logic_vector(7 DOWNTO 0)
		);
	END COMPONENT;
	
	COMPONENT KeySender IS
	PORT
	(
		Clk : IN std_logic;
		Reset : IN std_logic;
		Enable : IN std_logic;
		Txd_SendData : OUT std_logic_vector(7 DOWNTO 0);
		SendEnable : OUT std_logic;
		SendBusy : IN std_logic;
		P2KeyState : IN std_logic_vector(5 DOWNTO 0)
	);
	END COMPONENT;
	
	COMPONENT KeyRecver IS
	PORT
	(
		Clk : IN std_logic;
		Reset : IN std_logic;
		Enable : IN std_logic;
		Rxd_RecvData : IN std_logic_vector(7 DOWNTO 0);
		RecvAvail : IN std_logic;
		P2KeyState : OUT std_logic_vector(5 DOWNTO 0)
	);
	END COMPONENT;
	
	COMPONENT ScreenSender IS
	PORT
	(
		Clk : IN std_logic;
		Reset : IN std_logic;
		Enable : IN std_logic;
		Txd_SendData : OUT std_logic_vector(7 DOWNTO 0);
		SendEnable : OUT std_logic;
		SendBusy : IN std_logic;
		--- Memory Port
		SecoAddr : OUT std_logic_vector(9 DOWNTO 0);
		SecoReadData : IN std_logic_vector(15 DOWNTO 0)
	);
	END COMPONENT;

	COMPONENT ScreenRecver IS
	PORT
	(
		Clk : IN std_logic;
		Reset : IN std_logic;
		Enable : IN std_logic;
		Rxd_RecvData : IN std_logic_vector(7 DOWNTO 0);
		RecvAvail : IN std_logic;
		--- Memory Port
		SecoAddr : OUT std_logic_vector(9 DOWNTO 0);
		SecoWriteData : OUT std_logic_vector(15 DOWNTO 0);
		SecoWriteEnable : OUT std_logic
	);
	END COMPONENT;
	
	-- COM Ports
	SIGNAL COMDataIn : std_logic_vector(7 DOWNTO 0);
	SIGNAL COMDataOut : std_logic_vector(7 DOWNTO 0);
	SIGNAL COMSend : std_logic;
	SIGNAL COMSendBusy : std_logic;
	SIGNAL COMRecv : std_logic;
	-- KeyCoder Selector
	SIGNAL KeySenderEnable : std_logic;
	SIGNAL KeyRecverEnable : std_logic;
	-- Screen Selector
	SIGNAL ScreenSenderEnable : std_logic;
	SIGNAL ScreenRecverEnable : std_logic;
	-- Data Selector
	SIGNAL KeyDataOut : std_logic_vector(7 DOWNTO 0);
	SIGNAL KeySend : std_logic;
	SIGNAL ScreenDataOut : std_logic_Vector(7 DOWNTO 0);
	SIGNAL ScreenSend : std_logic;
	-- Key Recv
	SIGNAL P2RecvKeyState : std_logic_vector(5 DOWNTO 0);
	-- Screen Recv
	SIGNAL SecoReadAddr : std_logic_vector(9 DOWNTO 0);
	SIGNAL SecoWriteAddr : std_logic_vector(9 DOWNTO 0);
	SIGNAL SecoAddrSelector : std_logic;

BEGIN
	cCOMSend : async_transmitter PORT MAP(
		clk 	=> Clk,
		TxD_start 	=> COMSend,
		TxD_data 	=> COMDataOut,
		TxD 	 => TxD,
		TxD_busy => COMSendBusy );

	cCOMRecv : async_receiver PORT MAP(
		clk => Clk,
		RxD => RxD,
		RxD_data_ready => COMRecv,
		RxD_data => COMDataIn );
	
	cKeySend : KeySender PORT MAP(
		Clk => Clk,
		Reset => Reset,
		Enable => KeySenderEnable,
		Txd_SendData => KeyDataOut,
		SendEnable => KeySend,
		SendBusy => COMSendBusy,
		P2KeyState => LocalP2KeyState );

	cKeyRecver : KeyRecver PORT MAP(
		Clk => Clk,
		Reset => Reset,
		Enable => KeyRecverEnable,
		Rxd_RecvData => COMDataIn,
		RecvAvail => COMRecv,
		P2KeyState => P2RecvKeyState );

	cScreenSender : ScreenSender PORT MAP(
		Clk => Clk,
		Reset => Reset,
		Enable => ScreenSenderEnable,
		Txd_SendData => ScreenDataOut,
		SendEnable => ScreenSend,
		SendBusy => COMSendBusy,
		--- Memory Port
		SecoAddr => SecoReadAddr,
		SecoReadData => SecoReadData
	);
	
	cScreenRecver : ScreenRecver PORT MAP(
		Clk => Clk,
		Reset => Reset,
		Enable => ScreenRecverEnable,
		Rxd_RecvData => COMDataIn,
		RecvAvail => COMRecv,
		--- Memory Port
		SecoAddr => SecoWriteAddr,
		SecoWriteData => SecoWriteData,
		SecoWriteEnable => SecoWriteEnable
	);
	
	KeySenderEnable <= '1' WHEN GameMode = "11" ELSE
					   '0';
	KeyRecverEnable <= '1' WHEN GameMode = "10" ELSE
					   '0';
					   
	ScreenSenderEnable <= '1' WHEN GameMode = "10" ELSE
						  '0';
	ScreenRecverEnable <= '1' WHEN GameMode = "11" ELSE
					      '0';

	P2KeyState <= P2RecvKeyState WHEN GameMode = "10" ELSE
				  LocalP2KeyState;

	COMDataOut <= KeyDataOut WHEN GameMode = "11" ELSE
				  ScreenDataOut;
				  
	COMSend <= KeySend WHEN GameMode = "11" ELSE
			   ScreenSend WHEN GameMode = "10" ELSE
			   '0';

	SecoAddr <= SecoReadAddr WHEN GameMode = "10" ELSE
				SecoWriteAddr;
				
				
	DebugSignal <= (KeyRecverEnable, COMDataIn(0), COMDataIn(1));
END rtl;
